﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using Microsoft.Office.Interop.Outlook;
using Utilities;
using Office = Microsoft.Office.Core;
using Outlook = Microsoft.Office.Interop.Outlook;

namespace OutlookAddin
{
    partial class MyOutlook
    {
        #region Form Region Factory

        [Microsoft.Office.Tools.Outlook.FormRegionMessageClass(Microsoft.Office.Tools.Outlook.FormRegionMessageClassAttribute.Note)]
        [Microsoft.Office.Tools.Outlook.FormRegionName("OutlookAddin.MyOutlook")]
        public partial class MyOutlookFactory
        {
            // Occurs before the form region is initialized.
            // To prevent the form region from appearing, set e.Cancel to true.
            // Use e.OutlookItem to get a reference to the current Outlook item.
            private void MyOutlookFactory_FormRegionInitializing(object sender, Microsoft.Office.Tools.Outlook.FormRegionInitializingEventArgs e)
            {
            }
        }

        #endregion
        private Microsoft.Office.Interop.Outlook.Application outlookApp = Globals.ThisAddIn.Application;
        private User _user = null;
        private User _receiver = null;
        private Explorer explorer;

        // Occurs before the form region is displayed.
        // Use this.OutlookItem to get a reference to the current Outlook item.
        // Use this.OutlookFormRegion to get a reference to the form region.
        private void MyOutlook_FormRegionShowing(object sender, System.EventArgs e)
        {
            explorer = outlookApp.ActiveExplorer();
        }

        // Occurs when the form region is closed.
        // Use this.OutlookItem to get a reference to the current Outlook item.
        // Use this.OutlookFormRegion to get a reference to the form region.
        private void MyOutlook_FormRegionClosed(object sender, System.EventArgs e)
        {
        }

        private void btnBasicEncrypt_Click(object sender, EventArgs e)
        {
            try
            {
                string err = ValidateInput();
                if (!err.Equals(string.Empty))
                {
                    System.Windows.Forms.MessageBox.Show(err, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }

                //hash input pass
                SHA256 sha = SHA256.Create();
                byte[] arrPass = sha.ComputeHash(Encoding.ASCII.GetBytes(tbPassword.Text));

                byte[] arrKey = null;
                //select algo
                SymmetricAlgorithm algo = null;
                switch (cbbAlgorith.Text)
                {
                    case "DES":
                        algo = new DESCryptoServiceProvider();
                        arrKey = new byte[8];
                        CopyBuffer(arrPass, arrKey, 8);
                        break;
                    case "TripleDES":
                        algo = new TripleDESCryptoServiceProvider();
                        arrKey = new byte[24];
                        CopyBuffer(arrPass, arrKey, 24);
                        break;
                    case "RC2":
                        algo = new RC2CryptoServiceProvider();
                        arrKey = new byte[16];
                        CopyBuffer(arrPass, arrKey, 16);
                        break;
                    case "Rijndael":
                        algo = new RijndaelManaged();
                        arrKey = new byte[16];
                        CopyBuffer(arrPass, arrKey, 16);
                        break;
                }

                Inspector inspector = outlookApp.ActiveInspector();
                if (inspector != null)
                {
                    MailItem mail = inspector.CurrentItem as MailItem;

                    if (mail != null)
                    {
                        mail.Body = EncryptionProvider.Encrypt(algo, mail.Body, arrKey, arrKey, PaddingMode.ANSIX923, CipherMode.CBC);
                        tbPassword.Text = string.Empty;
                    }
                }
            }
            catch (System.Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
        }

        private string ValidateInput()
        {
            if (tbPassword.Text.Equals(string.Empty))
            {
                return "làm ơn chọn mật khẩu của bạn!";
            }

            if (cbbAlgorith.Text.Equals(string.Empty))
            {
                return "Làm ơn chọn thuật toán mã hóa của bạn!";
            }

            return string.Empty;
        }

        private void CopyBuffer(byte[] src, byte[] des, int length)
        {
            if (src.Length < length)
                return;
            int i;
            for (i = 0; i < length; i++)
            {
                des[i] = src[i];
            }
        }

        private void btnBasicDecrypt_Click(object sender, EventArgs e)
        {
            try
            {
                string err = ValidateInput();
                if (!err.Equals(string.Empty))
                {
                    MessageBox.Show(err, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }

                //hash input pass
                SHA256 sha = SHA256.Create();
                byte[] arrPass = sha.ComputeHash(Encoding.ASCII.GetBytes(tbPassword.Text));

                byte[] arrKey = null;
                //select algo
                SymmetricAlgorithm algo = null;
                switch (cbbAlgorith.Text)
                {
                    case "DES":
                        algo = new DESCryptoServiceProvider();
                        arrKey = new byte[8];
                        CopyBuffer(arrPass, arrKey, 8);
                        break;
                    case "TripleDES":
                        algo = new TripleDESCryptoServiceProvider();
                        arrKey = new byte[24];
                        CopyBuffer(arrPass, arrKey, 24);
                        break;
                    case "RC2":
                        algo = new RC2CryptoServiceProvider();
                        arrKey = new byte[16];
                        CopyBuffer(arrPass, arrKey, 16);
                        break;
                    case "Rijndael":
                        algo = new RijndaelManaged();
                        arrKey = new byte[16];
                        CopyBuffer(arrPass, arrKey, 16);
                        break;
                }

                Inspector inspector = outlookApp.ActiveInspector();
                if (inspector != null)
                {
                    MailItem mail = inspector.CurrentItem as MailItem;

                    if (mail != null)
                    {
                        mail.Body = EncryptionProvider.Decrypt(algo, mail.Body, arrKey, arrKey, PaddingMode.ANSIX923, CipherMode.CBC);
                        tbPassword.Text = string.Empty;
                    }
                }
            }
            catch (System.Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
        }

        private void btnImportYourInfo_Click(object sender, EventArgs e)
        {
            try
            {
                openFileDialog1.Title = "Import your xml file";
                openFileDialog1.Filter = "XML file (.xml) | *.xml";
                openFileDialog1.FileName = "";
                openFileDialog1.Multiselect = false;
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    this._user = this.ImportUserInfo(openFileDialog1.FileName);
                    if (_user != null)
                    {
                        btnDecript.Enabled = true;
                        btnEncrypt.Enabled = true;
                        btnSign.Enabled = true;
                        btnVerifySign.Enabled = true;
                        btnImportFriendInfo.Enabled = true;
                        groupPanel2.Enabled = true;
                    }
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message, Utility.ExceptionTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private User ImportUserInfo(string xmlFile)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(User));
            TextReader reader = null;
            User user = new User();
            try
            {
                reader = new StreamReader(openFileDialog1.FileName);
                user = (User)serializer.Deserialize(reader);
                return user;
            }
            catch (System.Exception)
            {
                MessageBox.Show("Cannot load user database.", Utility.ExceptionTitle, MessageBoxButtons.OK, MessageBoxIcon.Stop);
                return null;
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
            }
        }

        private void btnImportFriendInfo_Click(object sender, EventArgs e)
        {
            try
            {
                openFileDialog1.Title = "Import your xml file";
                openFileDialog1.Filter = "XML file (.xml)| *.xml";
                openFileDialog1.FileName = "";
                openFileDialog1.Multiselect = false;
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    this._receiver = this.ImportUserInfo(openFileDialog1.FileName);
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message, Utility.ExceptionTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void btnEncrypt_Click(object sender, EventArgs e)
        {
            string content = string.Empty;

            Inspector inspector = outlookApp.ActiveInspector();
            if (inspector != null)
            {
                MailItem mail = inspector.CurrentItem as MailItem;
                if (mail != null)
                {
                    content = mail.Body;
                }
            }

            if (content.Equals(string.Empty))
                return;

            EncryptFrm encryptForm = new EncryptFrm(this._receiver);
            if (encryptForm.ShowDialog() == DialogResult.OK)
            {
                byte[] key = EncryptionProvider.GenerateKeyBytes(encryptForm.EncryptionAlgorithm);

                RSACryptoServiceProvider rsa = null;
                if (encryptForm.JustMe)
                {
                    rsa = _user.GetRSAKeyPair(false);
                }
                else
                {

                    rsa = _receiver.GetRSAKeyPair(false);
                }

                Utility.WriteFile("encrypt.tmp", content);

                Stream ins = new StreamReader("encrypt.tmp").BaseStream;
                Stream outs = new StreamWriter(encryptForm.OutputPath, false).BaseStream;
                try
                {
                    EncryptionProvider.Encrypt(ins, outs,
                        encryptForm.EncryptionAlgorithm,
                        key,
                        rsa,
                        encryptForm.PaddingMode,
                        encryptForm.CipherMode);

                    MessageBox.Show("Mã hóa thành công! \n file đã mã hóa được lưu ở: " + encryptForm.OutputPath, Utility.InformTitle);
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show(ex.Message, Utility.ExceptionTitle);
                    return;
                }
                finally
                {
                    File.Delete("encrypt.tmp");
                }
            }
        }

        private void btnDecript_Click(object sender, EventArgs e)
        {
            ConfirmPassFrm frm = new ConfirmPassFrm(this._user);
            if (frm.ShowDialog() == DialogResult.OK)
            {
                openFileDialog1.Title = "Select file to decrypt ... ";
                openFileDialog1.FileName = string.Empty;
                openFileDialog1.Filter = "Encrypted file|*.enc";
                openFileDialog1.Multiselect = false;
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    string filePath = openFileDialog1.FileName;
                    Stream enc = new StreamReader(filePath).BaseStream;

                    string outputPath = filePath.Remove(filePath.LastIndexOf('.')) + ".txt";

                    Stream dec = new StreamWriter(outputPath).BaseStream;

                    RSACryptoServiceProvider rsa = this._user.GetRSAKeyPair(true);
                    try
                    {
                        EncryptionProvider.Decrypt(enc, dec, rsa);

                        MessageBox.Show("Giải mã thành công! \n File đã giải mã được lưu ở: " + outputPath, Utility.InformTitle);
                    }
                    catch (System.Exception ex)
                    {
                        MessageBox.Show(ex.Message, Utility.ExceptionTitle);
                        return;
                    }
                }
            }
        }

        private void btnSign_Click(object sender, EventArgs e)
        {
            try
            {
                ConfirmPassFrm frm = new ConfirmPassFrm(this._user);
                if (frm.ShowDialog() == DialogResult.OK)
                {
                    saveFileDialog1.Title = "Save signed file ... ";
                    saveFileDialog1.FileName = string.Empty;
                    saveFileDialog1.Filter = "Signed file (.sig) | *.sig";
                    if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                    {
                        Inspector inspector = outlookApp.ActiveInspector();
                        if (inspector != null)
                        {
                            MailItem mail = inspector.CurrentItem as MailItem;

                            if (mail != null)
                            {
                                string content = mail.Body;

                                Utility.WriteFile("sig.tmp", content);

                                Stream inStream = new StreamReader("sig.tmp").BaseStream;
                                Stream outStream = new StreamWriter(saveFileDialog1.FileName).BaseStream;
                                RSACryptoServiceProvider rsa = this._user.GetRSAKeyPair(true);
                                EncryptionProvider.Sign(inStream, outStream, rsa, Utility.HashAlgo);
                            }
                        }
                    }
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message, Utility.ExceptionTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                File.Delete("sig.tmp");
            }
        }

        private void btnVerifySign_Click(object sender, EventArgs e)
        {
            try
            {
                openFileDialog1.Title = "Select your signed file ... ";
                openFileDialog1.FileName = string.Empty;
                openFileDialog1.Filter = "Signed file (.sig) | *.sig";
                openFileDialog1.Multiselect = false;
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    string sFileSig = openFileDialog1.FileName;

                    Inspector inspector = outlookApp.ActiveInspector();
                    if (inspector != null)
                    {
                        MailItem mail = inspector.CurrentItem as MailItem;

                        if (mail != null)
                        {
                            string content = mail.Body;

                            Utility.WriteFile("sig.tmp", content);
                        }
                    }

                    Stream inStream = new StreamReader("sig.tmp").BaseStream;
                    Stream signStream = new StreamReader(sFileSig).BaseStream;
                    RSACryptoServiceProvider rsa = this._user.GetRSAKeyPair(false);
                    if (EncryptionProvider.Verify(inStream, signStream, rsa, Utility.HashAlgo))
                    {
                        MessageBox.Show("Chữ ký đúng của " + this._user.ToString(), Utility.InformTitle);
                    }
                    else
                        MessageBox.Show("Chữ ký không đúng.", Utility.InformTitle);
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message, Utility.ExceptionTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
}
